/*******************************************************************************
 * Copyright (c) 2000, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.destiny.msglipse.component;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Sash;

public class MySashForm extends Composite {

	/**
	 * The width of all sashes in the form.
	 */
	public int SASH_WIDTH = 3;

	int sashStyle;
	Sash sash;
	Control left;
	Control right;
	Color background = null;
	Color foreground = null;
	Control[] controls = new Control[0];
	Control maxControl = null;
	Listener sashListener;
	static final int DRAG_MINIMUM = 20;

	public MySashForm(Composite parent, int style) {
		super(parent, checkStyle(style));
		super.setLayout(new MySashFormLayout());
		sashStyle = ((style & SWT.VERTICAL) != 0) ? SWT.HORIZONTAL : SWT.VERTICAL;
		if ((style & SWT.BORDER) != 0)
			sashStyle |= SWT.BORDER;
		if ((style & SWT.SMOOTH) != 0)
			sashStyle |= SWT.SMOOTH;
		sashListener = new Listener() {
			public void handleEvent(Event e) {
				onDragSash(e);
			}
		};
		sash = createSash();
	}

	static int checkStyle(int style) {
		int mask = SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
		return style & mask;
	}

	Sash createSash() {
		Sash sash = new Sash(this, sashStyle);
		sash.setBackground(background);
		sash.setForeground(foreground);
		sash.setToolTipText(getToolTipText());
		sash.addListener(SWT.Selection, sashListener);
		return sash;
	}

	public int getOrientation() {
		// checkWidget();
		return (sashStyle & SWT.VERTICAL) != 0 ? SWT.HORIZONTAL : SWT.VERTICAL;
	}

	public int getSashWidth() {
		checkWidget();
		return SASH_WIDTH;
	}

	public int getStyle() {
		int style = super.getStyle();
		style |= getOrientation() == SWT.VERTICAL ? SWT.VERTICAL : SWT.HORIZONTAL;
		if ((sashStyle & SWT.SMOOTH) != 0)
			style |= SWT.SMOOTH;
		return style;
	}

	public Control getMaximizedControl() {
		// checkWidget();
		return this.maxControl;
	}

	Control[] getControls(boolean onlyVisible) {
		Control[] children = getChildren();
		Control[] result = new Control[0];
		for (int i = 0; i < children.length; i++) {
			if (children[i] instanceof Sash)
				continue;
			if (onlyVisible && !children[i].getVisible())
				continue;

			Control[] newResult = new Control[result.length + 1];
			System.arraycopy(result, 0, newResult, 0, result.length);
			newResult[result.length] = children[i];
			result = newResult;
		}
		return result;
	}

	void onDragSash(Event event) {

		Control c1 = left;
		Control c2 = right;
		Rectangle b1 = c1.getBounds();
		Rectangle b2 = c2.getBounds();

		Rectangle sashBounds = sash.getBounds();
		boolean correction = false;
		if (getOrientation() == SWT.HORIZONTAL) {
			correction = b1.width < DRAG_MINIMUM || b2.width < DRAG_MINIMUM;
			int totalWidth = b2.x + b2.width - b1.x;
			int shift = event.x - sashBounds.x;
			b1.width += shift;
			b2.x += shift;
			b2.width -= shift;
			if (b1.width < DRAG_MINIMUM) {
				b1.width = DRAG_MINIMUM;
				b2.x = b1.x + b1.width + sashBounds.width;
				b2.width = totalWidth - b2.x;
				event.x = b1.x + b1.width;
				event.doit = false;
			}
			if (b2.width < DRAG_MINIMUM) {
				b1.width = totalWidth - DRAG_MINIMUM - sashBounds.width;
				b2.x = b1.x + b1.width + sashBounds.width;
				b2.width = DRAG_MINIMUM;
				event.x = b1.x + b1.width;
				event.doit = false;
			}
		} else {
			correction = b1.height < DRAG_MINIMUM || b2.height < DRAG_MINIMUM;
			int totalHeight = b2.y + b2.height - b1.y;
			int shift = event.y - sashBounds.y;
			b1.height += shift;
			b2.y += shift;
			b2.height -= shift;
			if (b1.height < DRAG_MINIMUM) {
				b1.height = DRAG_MINIMUM;
				b2.y = b1.y + b1.height + sashBounds.height;
				b2.height = totalHeight - b2.y;
				event.y = b1.y + b1.height;
				event.doit = false;
			}
			if (b2.height < DRAG_MINIMUM) {
				b1.height = totalHeight - DRAG_MINIMUM - sashBounds.height;
				b2.y = b1.y + b1.height + sashBounds.height;
				b2.height = DRAG_MINIMUM;
				event.y = b1.y + b1.height;
				event.doit = false;
			}
		}
		if (correction || (event.doit && event.detail != SWT.DRAG)) {
			c1.setBounds(b1);
			sash.setBounds(event.x, event.y, event.width, event.height);
			c2.setBounds(b2);
		}
	}

	public void setBackground(Color color) {
		super.setBackground(color);
		background = color;
		sash.setBackground(background);
	}

	public void setForeground(Color color) {
		super.setForeground(color);
		foreground = color;
		sash.setForeground(foreground);
	}

	public void setLayout(Layout layout) {
		checkWidget();
		return;
	}

	public void setMaximizedControl(Control control) {
		checkWidget();
		if (control == null) {
			if (maxControl != null) {
				this.maxControl = null;
				layout(false);
				left.setVisible(true);
				right.setVisible(true);
			}
			return;
		}

		left.setVisible(false);
		right.setVisible(false);
		maxControl = control;
		layout(false);
	}

	public void setSashWidth(int width) {
		checkWidget();
		if (SASH_WIDTH == width)
			return;
		SASH_WIDTH = width;
		layout(false);
	}

	public void setToolTipText(String string) {
		super.setToolTipText(string);
		sash.setToolTipText(string);
	}

	public Control getLeft() {
		return left;
	}

	public void setLeft(Control left) {
		this.left = left;
		left.setParent(this);
	}

	public Control getRight() {
		return right;
	}

	public void setRight(Control right) {
		this.right = right;
		right.setParent(this);
		Rectangle rect = getClientArea();
		int rightw = right.getBounds().width;
		sash.setBounds(rect.width - rightw - getSashWidth(), rect.y, getSashWidth(), rect.height);
		right.setBounds(rect.width - rightw, rect.y, rightw, rect.height);
	}

}
